Skip to content

Expose managed approval requirement on permission requests - #2080

Open
joshspicer wants to merge 14 commits into
github:mainfrom
joshspicer:joshspicer/managed-approval-required-sdk
Open

Expose managed approval requirement on permission requests#2080
joshspicer wants to merge 14 commits into
github:mainfrom
joshspicer:joshspicer/managed-approval-required-sdk

Conversation

@joshspicer

@joshspicer joshspicer commented Jul 24, 2026

Copy link
Copy Markdown

Why

Enterprise-managed permission ask rules must be answered by a person. SDK hosts need to distinguish those requests from ordinary permission prompts that client settings may auto-approve.

This is the public SDK contract for:

The initial runtime scope supports managed Shell, Read, Edit, and Domain selectors. Tool and MCP selectors are deferred.

What

Exposes optional managed-approval metadata on public permission request and permission.requested event paths in every SDK:

  • Node.js: managedApprovalRequired
  • Python: managed_approval_required
  • Go: ManagedApprovalRequired and RequiresManagedApproval()
  • .NET: ManagedApprovalRequired
  • Rust: managed_approval_required
  • Java: getManagedApprovalRequired() and PermissionRequest.fromJsonValue(...) for generated event values

Built-in approve-all handlers now approve ordinary requests but return no-result for managed requests, leaving them pending for an explicit human-facing host decision. Custom-handler documentation checks the managed flag before kind-specific auto-approval.

Python, Go, and Rust codegen augment the pinned CLI schema until the runtime schema update ships in the repository's published CLI dependency. Regeneration is deterministic and the committed generated diff contains only the managed approval field.

Validation

  • Node.js: focused codegen/client/type tests (161 passed), typecheck, build, format check, lint (0 errors)
  • Python: managed permission tests (3 passed), relevant unit suite (121 passed), Ruff, ty, and Python docs validation
  • Go: go test ./..., golangci-lint run ./..., and Go docs validation
  • .NET: managed permission tests (3 passed), relevant unit/serialization suite (53 passed), full build, format check, and C# docs validation; the full local E2E suite had one unrelated abort timeout that passed on targeted rerun
  • Rust: 204 library tests, 9 generated API/type tests, Clippy with -D warnings, nightly rustfmt, and reproducible codegen; the full replay E2E run had two unrelated snapshot mismatches
  • Java: mvn verify, focused permission/dispatcher tests, Spotless, Checkstyle, and Java docs validation
  • Python/Go/Rust codegen reproducibility checks passed
  • linked runtime + SDK + VS Code manual validation confirmed managed asks reach client UI and repeated asks do not persist approval

Copilot AI review requested due to automatic review settings July 24, 2026 21:29

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Exposes managed approval requirements to TypeScript permission handlers.

Changes:

  • Adds optional managedApprovalRequired metadata.
  • Adds package-root type coverage.
Show a summary per file
File Description
nodejs/src/types.ts Overlays managed approval metadata onto permission requests.
nodejs/test/session-event-types.test.ts Verifies the field is publicly importable.

Review details

  • Files reviewed: 2/2 changed files
  • Comments generated: 3
  • Review effort level: Medium

Comment thread nodejs/src/types.ts Outdated
Comment thread nodejs/src/types.ts Outdated
Comment thread nodejs/src/types.ts Outdated
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: 18f1bbc1-6001-43e2-b293-724505087f6a
Copilot AI review requested due to automatic review settings July 28, 2026 16:26
@SteveSandersonMS
SteveSandersonMS force-pushed the joshspicer/managed-approval-required-sdk branch from 13c3d37 to 03184d2 Compare July 28, 2026 16:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

Comments suppressed due to low confidence (1)

nodejs/src/types.ts:1108

  • This overlay only updates the standalone type and PermissionHandler; the public SessionEvent/PermissionRequestedData types still come from the generated schema, where permissionRequest lacks this property. Consequently, an event-only host (the documented path when onPermissionRequest is omitted) cannot compile event.data.permissionRequest.managedApprovalRequired even though the runtime sends it. Please overlay the permission.requested event payload as well so every public permission-request surface exposes the metadata.
export type PermissionRequest = GeneratedPermissionRequest & {
    readonly managedApprovalRequired?: boolean;
};
  • Files reviewed: 2/2 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: c7f00b84-b0a7-4cdf-aca9-ffd49737f26e
Copilot AI review requested due to automatic review settings July 28, 2026 17:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

  • Files reviewed: 2/2 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 28, 2026 20:35

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

Comments suppressed due to low confidence (1)

nodejs/src/types.ts:1145

  • The behavior change leaves the public README inaccurate: nodejs/README.md:39, :133, and :856-866 still describe approveAll as allowing every request/tool call. With a managed request it now returns no-result, so following those docs can leave execution pending until the consumer explicitly resolves the permission. Please update the permission-handling docs and examples to describe this exception and how hosts should resolve it.
export const approveAll: PermissionHandler = (request) =>
    request.managedApprovalRequired ? { kind: "no-result" } : { kind: "approve-once" };
  • Files reviewed: 4/4 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

@joshspicer
joshspicer marked this pull request as ready for review July 28, 2026 22:24
@joshspicer
joshspicer requested a review from a team as a code owner July 28, 2026 22:24
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 28, 2026 22:40

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

Comments suppressed due to low confidence (1)

nodejs/README.md:869

  • The immediately following custom-handler example still returns approve-once for every non-shell request without checking managedApprovalRequired. Copying it therefore auto-approves managed Read, Edit, or Domain asks, contradicting the human-approval requirement documented here. Update that example to route flagged requests through a human confirmation flow (or leave them unanswered).
For requests with `managedApprovalRequired: true`, `approveAll` returns `{ kind: "no-result" }`. The request remains pending and the host must present a human-facing confirmation flow to resolve it explicitly.
  • Files reviewed: 5/5 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

@joshspicer

Copy link
Copy Markdown
Author

Linked end-to-end validation completed against SDK head 0da1c5995fa4, runtime head 18b743d00dcd, and the merged VS Code host integration.

Cross-layer audit of the latest runtime session and AHP transcript confirmed:

  • 12 public SDK permission.requested events exposed managedApprovalRequired: true on the permission request and prompt request
  • all 12 requests completed through the SDK permission callback path
  • AHP rendered 12 human confirmation cards with exactly allow-once and skip; no allow-session option or selection appeared
  • managed denies produced no permission callback/confirmation and failed closed
  • direct allows completed without confirmation
  • the device policy resolved from the supported file source as source: device, deviceManaged: true

The assistant's final table overstated downstream tool success for two approved Domain asks (HTTP redirect/404) and mislabeled the api.github.com prompt; those are reporting/tool-result issues, not SDK permission-routing failures. The SDK contract and host behavior validated successfully.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 29, 2026 00:41

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

  • Files reviewed: 5/5 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

Files not reviewed (1)
  • go/rpc/zsession_events.go: Generated file
  • Files reviewed: 33/36 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 29, 2026 20:20

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

Files not reviewed (1)
  • go/rpc/zsession_events.go: Generated file
Comments suppressed due to low confidence (1)

java/src/main/java/com/github/copilot/rpc/PermissionHandler.java:60

  • APPROVE_ALL now returns no-result, but Java's protocol-v2 dispatch path explicitly rejects that value: RpcHandlerDispatcher.handlePermissionRequest lines 222-237 throws and then sends DENIED_COULD_NOT_REQUEST_FROM_USER. Consequently a managed request is denied rather than left pending for a human decision. The dispatcher must suppress the response for no-result (as the other SDKs do) before this handler can satisfy the documented contract.
    PermissionHandler APPROVE_ALL = (request,
            invocation) -> CompletableFuture.completedFuture(Boolean.TRUE.equals(request.getManagedApprovalRequired())
                    ? PermissionRequestResult.noResult()
                    : PermissionRequestResult.approveOnce());
  • Files reviewed: 30/33 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 29, 2026 21:51

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

Files not reviewed (1)
  • go/rpc/zsession_events.go: Generated file
Comments suppressed due to low confidence (1)

rust/src/session.rs:1526

  • This unwraps permissionRequest before constructing the public PermissionRequestData, changing extra from the full notification params to only the nested request. Existing handlers that read extra["permissionRequest"], promptRequest, or other top-level metadata will silently lose those values (the current E2E helper at rust/tests/e2e/permissions.rs:599-622 explicitly supports that shape), and it contradicts PermissionRequestData's documented “full params object” contract. Populate the new managed field from the nested value without replacing the existing extra payload, or explicitly preserve the wrapper for compatibility.
    let request_data = event_data
        .get("permissionRequest")
        .cloned()
        .unwrap_or_else(|| event_data.clone());
  • Files reviewed: 30/33 changed files
  • Comments generated: 1
  • Review effort level: Medium

Comment thread rust/src/session.rs Outdated
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 29, 2026 22:18

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

Files not reviewed (1)
  • go/rpc/zsession_events.go: Generated file
  • Files reviewed: 30/33 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 30, 2026 04:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

Files not reviewed (1)
  • go/rpc/zsession_events.go: Generated file
Comments suppressed due to low confidence (1)

dotnet/README.md:805

  • PermissionRequest is the generated base class and does not declare ManagedApprovalRequired; only the Shell/Write/Read/Url subclasses do (Generated/SessionEvents.cs:6928-7130). This custom-handler example therefore does not compile as written. Pattern-match the supported variants (as PermissionHandlers.cs does) before reading the property.
        if (request.ManagedApprovalRequired == true)
        {
            return PermissionDecision.NoResult();
        }
  • Files reviewed: 25/26 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 30, 2026 04:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

Files not reviewed (1)
  • go/rpc/zsession_events.go: Generated file
Comments suppressed due to low confidence (3)

python/README.md:836

  • This async example has the same union issue: several valid permission variants do not define managed_approval_required, so it raises before reaching the asynchronous approval logic. Guard the optional per-variant attribute as the built-in handler does.
    if request.managed_approval_required is True:

python/README.md:811

  • The generated PermissionRequest union still includes MCP, custom-tool, memory, hook, and extension variants without this attribute. This unconditional access raises AttributeError when the handler receives one of those ordinary requests, so the documented handler fails instead of applying its kind-specific decision; use the same getattr guard as PermissionHandler.approve_all.

This issue also appears on line 836 of the same file.

    if request.managed_approval_required is True:

nodejs/README.md:881

  • PermissionRequest includes variants such as MCP and custom-tool that do not declare managedApprovalRequired, so this direct property access does not type-check for the generated discriminated union. The built-in implementation already uses an in guard; the public example needs the same narrowing or consumers cannot compile it.
        if (request.managedApprovalRequired === true) {
  • Files reviewed: 25/26 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 30, 2026 04:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

Files not reviewed (1)
  • go/rpc/zsession_events.go: Generated file
  • Files reviewed: 25/26 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 30, 2026 05:18

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

Files not reviewed (1)
  • go/rpc/zsession_events.go: Generated file
  • Files reviewed: 25/26 changed files
  • Comments generated: 0 new
  • Review effort level: Medium

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants